#!/usr/bin/env python3 
# -*- coding:utf-8 -*-

import re

# re 模块为 python 中的正则表达式
"""
正则表达式简要:
\d 可以匹配一个数字 \d\d\d 就是匹配3个数字
\w 可以匹配一个字母或者数字 \w\w\d 可以匹配 'py3'
.  可以匹配任意字符, 'py.' 可以匹配 'pyc' 'pyd' 'py~'等

要匹配变长的字符,可以使用*,表示任意字符,包括0,用+表示至少1个字符,?表示0/1个,{n}表示 n个,{m,n}表示 m-n 个
\d{3}\s+\d{3,8}
\d{3}:表示匹配3个数字
\s:表示可以匹配一个空格(包括 tab 等空白符),所以\s+ 表示至少有一个空格
\d{3,8}:表示可以匹配3-8个数字
综合起来,就是:可以匹配以任意空格隔开的带区号的电话号码


如果要匹配'010-12345'这样的电话号码呢,由于'-'是特殊字符,所以需要用'\'转义
所以上面的正则是:\ d{3}\-\d{3,8}

进阶:
要做更精确的匹配,可以用[]表示范围
[0-9a-zA-Z\_]:表示可以匹配一个数字,字母或下划线
[0-9a-zA-Z\_]+:表示可以匹配至少由一个数字,字母或者下划线组成的字符串
[a-zA-Z\_][0-9a-zA-Z\_]*:表示可以匹配字母或下划线开头,后面接任意一个数字,字母或者下划线组成的字符串,也就是 python 的合法变量
[a-zA-Z\_][0-9a-zA-Z\_]{0, 19}更精确地限制了变量的长度是1-20个字符（前面1个字符+后面最多19个字符

A|B :可以匹配 A 或 B, (P|p)ython 可以匹配: Python python

^:表示行的开头, ^\d 表示必须以数字开头
$:表示行的结束

"""
s = 'ABC\\-001'  # Python的字符串,Python的字符串本身也用\转义
print(s)  # 实际输出:ABC\-001

# 使用 r 前缀
s = r'ABC\-001'
print(s)
# 对应的正则表达式字符串不变：
# 'ABC\-001'

pattern = r'^\d{3}\-\d{3,8}$'
res = re.match(pattern, '010-12345')
print(res)

print(re.match(pattern, '010 12345'))
# match()方法判断是否匹配，如果匹配成功，返回一个Match对象，否则返回None

test = 'abcd'
if re.match(r'\w{1,6}', test):
    print('ok')
else:
    print('no ok')

# 切分字符串
# 用正则表达式切分字符串比用固定的字符串更灵活

s = 'a b  c'.split(' ')
print(s)  # ['a', 'b', '', 'c'],无法识别连续的空格

s = re.split(r'\s+', 'a b   c')
print(s)  # ['a', 'b', 'c'],无论多少个空格都能被分割

# 加入 , 试试
s = re.split(r'[\s,]+', 'a,b,c   d')
print(s)  # ['a', 'b', 'c', 'd']

# 加入 ; 试试
s = re.split(r'[\s,;]+', 'a,b;; c  d')
print(s)

# 分组
# 除了简单的判断是否匹配之外,正则表达式还有提取子串的强大功能,用()表示的就是要提取的分组 group
# ^(\d{3})-(\d{3,8}) 分别定义了两个组,可以直接从匹配的字符串中提取出区号和本地号码
m = re.match(r'^(\d{3})-(\d{3,8})$', '010-12345')
print(m.group(0))  # 010-12345
print(m.group(1))  # 010
print(m.group(2))  # 12345
# 正则表达式中定义了组，就可以在Match对象上用group()方法提取出子串来
# 注意: group(0) 永远是原始字符串,  group(1) 表示第一个, group(2)表示2个


# 贪婪匹配
# 正则表达式默认是贪婪匹配,也就是匹配尽可能多的字符串

re.match(r'^(\d+)(0*)$', '1020300').group()
# ('1020300', '')
# 由于 \d+ 采用贪婪匹配,直接把后面的0全部匹配 ,结果0* 只能匹配空字符串了
# 修改成 \d+?


"""
编译:
当我们在 python 中使用正则表达式的时候, re 模块内部会干两件事情:
1,编译正则表达式,如果正则表达式的字符串本身不合法,会报错
2,用编译后的正则表达式去匹配字符串

如果一个正则表达式要重复使用几千次,处于效率的考虑,我们可以预编译该正则表达式,接下来重复使用的时候就不需要编译了,直接匹配

# 编译
re_tele = re.compile(r'^(\d{3})-(\d{3,8})$')
# 使用
re_tele.match('010-123').groups()

编译后生成Regular Expression对象，由于该对象自己包含了正则表达式，所以调用对应的方法时不用给出正则字符串
"""
